package pl.edu.agh.gp.basics;

import org.jgap.InvalidConfigurationException;
import org.jgap.gp.CommandGene;
import org.jgap.gp.function.*;
import org.jgap.gp.impl.GPConfiguration;
import org.jgap.gp.impl.GPGenotype;
import org.jgap.gp.terminal.False;
import org.jgap.gp.terminal.Terminal;
import org.jgap.gp.terminal.True;
import org.jgap.gp.terminal.Variable;
import pl.edu.agh.gp.common.GenotypeProvider;

import java.util.List;

import static org.jgap.gp.CommandGene.BooleanClass;
import static org.jgap.gp.CommandGene.DoubleClass;
import static org.jgap.gp.CommandGene.VoidClass;

public class BasicGenotypeProvider extends GenotypeProvider {

    public GPGenotype getBuyOrSellGenotype(GPConfiguration conf, int maxNodes) throws InvalidConfigurationException {
        CommandGene[][] nodeSets = {{
                openPrice = Variable.create(conf, "OpenPrice", DoubleClass),
                highPrice = Variable.create(conf, "HighPrice", DoubleClass),
                lowPrice = Variable.create(conf, "LowPrice", DoubleClass),
                closePrice = Variable.create(conf, "ClosePrice", DoubleClass),
                volume = Variable.create(conf, "Volume", DoubleClass),
                prices = Variable.create(conf, "Prices", List.class),

                new SubProgram(conf, new Class[] {VoidClass, BooleanClass}),
                new SubProgram(conf, new Class[] {VoidClass, DoubleClass}),
                new Add(conf,DoubleClass),
                new Subtract(conf, DoubleClass),
                new Multiply(conf, DoubleClass),
                new And(conf),
                new True(conf),
                new False(conf),
                new Terminal(conf, DoubleClass, 2.0d, 10.0d, true)
        }};

        return GPGenotype.randomInitialGenotype(conf, new Class[] {BooleanClass}, new Class[][]{{}}, nodeSets, maxNodes, true);
    }

    public GPGenotype getSharesAmountGenotype(GPConfiguration conf, int maxNodes) throws InvalidConfigurationException{
        CommandGene[][] nodeSets = {{
                openPrice = Variable.create(conf, "OpenPrice", DoubleClass),
                highPrice = Variable.create(conf, "HighPrice", DoubleClass),
                lowPrice = Variable.create(conf, "LowPrice", DoubleClass),
                closePrice = Variable.create(conf, "ClosePrice", DoubleClass),
                volume = Variable.create(conf, "Volume", DoubleClass),
                prices = Variable.create(conf, "Prices", List.class),

                new SubProgram(conf, new Class[] {VoidClass, BooleanClass}),
                new SubProgram(conf, new Class[] {VoidClass, DoubleClass}),
                new Add(conf,DoubleClass),
                new Subtract(conf, DoubleClass),
                new Multiply(conf, DoubleClass),
                new And(conf),
                new True(conf),
                new False(conf),
                new Terminal(conf, DoubleClass, 2.0d, 10.0d, true)
        }};

        return GPGenotype.randomInitialGenotype(conf, new Class[] {DoubleClass}, new Class[][]{{}}, nodeSets, maxNodes, true);
    }

    public GPGenotype getSimpleStockGenotype(GPConfiguration conf, int maxNodes) throws InvalidConfigurationException{
        CommandGene[][] nodeSets = {
                {
                        openPrice = Variable.create(conf, "OpenPrice", DoubleClass),
                        highPrice = Variable.create(conf, "HighPrice", DoubleClass),
                        lowPrice = Variable.create(conf, "LowPrice", DoubleClass),
                        closePrice = Variable.create(conf, "ClosePrice", DoubleClass),
                        volume = Variable.create(conf, "Volume", DoubleClass),
                        prices = Variable.create(conf, "Prices", List.class),

                        // Relational
                        new LesserThan(conf,DoubleClass),
                        new GreaterThan(conf,DoubleClass),
                        new LesserThan(conf,BooleanClass),
                        new GreaterThan(conf,BooleanClass),
                        new And(conf),

                        // Math
                        new Add(conf,DoubleClass),
                        new Subtract(conf, DoubleClass),
                        new Multiply(conf, DoubleClass),

                        // Terminals
                        new True(conf),
                        new False(conf),
                        new Terminal(conf, DoubleClass, 2.0d, 10.0d, true)
                },
                {
                        openPrice = Variable.create(conf, "OpenPrice", DoubleClass),
                        highPrice = Variable.create(conf, "HighPrice", DoubleClass),
                        lowPrice = Variable.create(conf, "LowPrice", DoubleClass),
                        closePrice = Variable.create(conf, "ClosePrice", DoubleClass),
                        new Add(conf,DoubleClass),
                        new Subtract(conf, DoubleClass),
                }
        };

        return GPGenotype.randomInitialGenotype(conf, new Class[] {BooleanClass, DoubleClass},  new Class[][]{{},{}}, nodeSets, maxNodes, true);
    }



    public GPGenotype getExtendedStockGenotype(GPConfiguration conf, int maxNodes) throws InvalidConfigurationException{
        CommandGene[] partialNodeSet = {
                openPrice = Variable.create(conf, "OpenPrice", DoubleClass),
                highPrice = Variable.create(conf, "HighPrice", DoubleClass),
                lowPrice = Variable.create(conf, "LowPrice", DoubleClass),
                closePrice = Variable.create(conf, "ClosePrice", DoubleClass),
                volume = Variable.create(conf, "Volume", DoubleClass),
                prices = Variable.create(conf, "Prices", List.class),

                // Relational
                new LesserThan(conf,DoubleClass),
                new GreaterThan(conf,DoubleClass),
                new LesserThan(conf,BooleanClass),
                new GreaterThan(conf,BooleanClass),
                new And(conf),
                new Or(conf),
                new Not(conf),
                new Xor(conf),
                new If(conf,DoubleClass),
                new If(conf,BooleanClass),
                new IfElse(conf,DoubleClass),
                new IfElse(conf,BooleanClass),

                // Math
                new Add(conf,DoubleClass),
                new Subtract(conf, DoubleClass),
                new Multiply(conf, DoubleClass),
                new Max(conf,DoubleClass),
                new Min(conf,DoubleClass),
                new Sine(conf, DoubleClass),
                new Exp(conf, DoubleClass),
                new Pow(conf, DoubleClass),
                new ArcCosine(conf, DoubleClass),
                new ArcSine(conf, DoubleClass),
                new ArcTangent(conf, DoubleClass),
                new Ceil(conf, DoubleClass),
                new Cosine(conf, DoubleClass),
                new Floor(conf, DoubleClass),
                new Log(conf,DoubleClass),
                new Modulo(conf,DoubleClass),
                new Tangent(conf,DoubleClass),
                new Divide(conf, DoubleClass),

                // Terminals
                new True(conf),
                new False(conf),
                new Terminal(conf, DoubleClass, 2.0d, 10.0d, true)
        };

        return getGenotype(partialNodeSet,conf,maxNodes);
    }
}